"""
PWA (Progressive Web App) 支持服务

提供渐进式Web应用功能，包括：
- Service Worker管理
- 应用清单生成
- 离线缓存策略
- 推送通知支持
- 应用安装提示
- 后台同步
"""
import json
import hashlib
from typing import Dict, List, Any, Optional, Set
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from enum import Enum
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
pwa_logger = logging.getLogger('pwa_service')


class CacheStrategy(Enum):
    """缓存策略枚举"""
    CACHE_FIRST = "cache_first"
    NETWORK_FIRST = "network_first"
    CACHE_ONLY = "cache_only"
    NETWORK_ONLY = "network_only"
    STALE_WHILE_REVALIDATE = "stale_while_revalidate"


class NotificationType(Enum):
    """通知类型枚举"""
    INFO = "info"
    WARNING = "warning"
    ERROR = "error"
    SUCCESS = "success"
    REMINDER = "reminder"


@dataclass
class PWAManifest:
    """PWA应用清单"""
    name: str
    short_name: str
    description: str
    start_url: str = "/"
    display: str = "standalone"
    theme_color: str = "#2196F3"
    background_color: str = "#ffffff"
    orientation: str = "portrait-primary"
    scope: str = "/"
    lang: str = "zh-CN"
    icons: List[Dict[str, Any]] = field(default_factory=list)
    categories: List[str] = field(default_factory=list)
    screenshots: List[Dict[str, Any]] = field(default_factory=list)
    shortcuts: List[Dict[str, Any]] = field(default_factory=list)


@dataclass
class CacheRule:
    """缓存规则"""
    pattern: str
    strategy: CacheStrategy
    cache_name: str
    max_age: int = 86400  # 24小时
    max_entries: int = 100
    network_timeout: int = 3000  # 3秒


@dataclass
class PushNotification:
    """推送通知"""
    title: str
    body: str
    icon: str = ""
    badge: str = ""
    image: str = ""
    tag: str = ""
    data: Dict[str, Any] = field(default_factory=dict)
    actions: List[Dict[str, str]] = field(default_factory=list)
    timestamp: datetime = field(default_factory=datetime.now)
    ttl: int = 86400  # 24小时


class PWAService:
    """PWA支持服务"""
    
    def __init__(self):
        # PWA配置
        self.pwa_config = {
            'enable_service_worker': True,
            'enable_push_notifications': True,
            'enable_background_sync': True,
            'enable_offline_analytics': True,
            'cache_version': 'v1.0.0',
            'update_check_interval': 3600  # 1小时
        }
        
        # 默认缓存规则
        self.cache_rules = [
            CacheRule(
                pattern=r'\.(?:html|htm)$',
                strategy=CacheStrategy.NETWORK_FIRST,
                cache_name='pages',
                max_age=3600,
                max_entries=50
            ),
            CacheRule(
                pattern=r'\.(?:css|js)$',
                strategy=CacheStrategy.CACHE_FIRST,
                cache_name='static',
                max_age=86400 * 7,  # 7天
                max_entries=100
            ),
            CacheRule(
                pattern=r'\.(?:png|jpg|jpeg|gif|svg|webp)$',
                strategy=CacheStrategy.CACHE_FIRST,
                cache_name='images',
                max_age=86400 * 30,  # 30天
                max_entries=200
            ),
            CacheRule(
                pattern=r'/api/',
                strategy=CacheStrategy.NETWORK_FIRST,
                cache_name='api',
                max_age=300,  # 5分钟
                max_entries=50,
                network_timeout=5000
            )
        ]
        
        # 推送通知订阅
        self.push_subscriptions: Set[str] = set()
        
        # 后台同步任务
        self.background_sync_tasks: List[Dict[str, Any]] = []
        
        # 应用更新状态
        self.update_available = False
        self.last_update_check = datetime.now()
    
    def generate_manifest(self, app_config: Dict[str, Any]) -> PWAManifest:
        """生成PWA应用清单"""
        try:
            manifest = PWAManifest(
                name=app_config.get('name', '学术研究自动化系统'),
                short_name=app_config.get('short_name', '研究助手'),
                description=app_config.get('description', '智能化学术研究辅助工具'),
                start_url=app_config.get('start_url', '/'),
                display=app_config.get('display', 'standalone'),
                theme_color=app_config.get('theme_color', '#2196F3'),
                background_color=app_config.get('background_color', '#ffffff'),
                orientation=app_config.get('orientation', 'portrait-primary'),
                scope=app_config.get('scope', '/'),
                lang=app_config.get('lang', 'zh-CN')
            )
            
            # 添加图标
            manifest.icons = [
                {
                    "src": "/static/icons/icon-72x72.png",
                    "sizes": "72x72",
                    "type": "image/png",
                    "purpose": "maskable any"
                },
                {
                    "src": "/static/icons/icon-96x96.png",
                    "sizes": "96x96",
                    "type": "image/png",
                    "purpose": "maskable any"
                },
                {
                    "src": "/static/icons/icon-128x128.png",
                    "sizes": "128x128",
                    "type": "image/png",
                    "purpose": "maskable any"
                },
                {
                    "src": "/static/icons/icon-144x144.png",
                    "sizes": "144x144",
                    "type": "image/png",
                    "purpose": "maskable any"
                },
                {
                    "src": "/static/icons/icon-152x152.png",
                    "sizes": "152x152",
                    "type": "image/png",
                    "purpose": "maskable any"
                },
                {
                    "src": "/static/icons/icon-192x192.png",
                    "sizes": "192x192",
                    "type": "image/png",
                    "purpose": "maskable any"
                },
                {
                    "src": "/static/icons/icon-384x384.png",
                    "sizes": "384x384",
                    "type": "image/png",
                    "purpose": "maskable any"
                },
                {
                    "src": "/static/icons/icon-512x512.png",
                    "sizes": "512x512",
                    "type": "image/png",
                    "purpose": "maskable any"
                }
            ]
            
            # 添加应用分类
            manifest.categories = [
                "education",
                "productivity",
                "utilities"
            ]
            
            # 添加快捷方式
            manifest.shortcuts = [
                {
                    "name": "新建项目",
                    "short_name": "新建",
                    "description": "创建新的研究项目",
                    "url": "/projects/new",
                    "icons": [
                        {
                            "src": "/static/icons/shortcut-new.png",
                            "sizes": "96x96"
                        }
                    ]
                },
                {
                    "name": "文献分析",
                    "short_name": "分析",
                    "description": "进行文献分析",
                    "url": "/analysis",
                    "icons": [
                        {
                            "src": "/static/icons/shortcut-analysis.png",
                            "sizes": "96x96"
                        }
                    ]
                },
                {
                    "name": "协作空间",
                    "short_name": "协作",
                    "description": "访问协作空间",
                    "url": "/collaboration",
                    "icons": [
                        {
                            "src": "/static/icons/shortcut-collab.png",
                            "sizes": "96x96"
                        }
                    ]
                }
            ]
            
            pwa_logger.info("PWA清单生成完成")
            return manifest
            
        except Exception as e:
            pwa_logger.error(f"PWA清单生成失败: {str(e)}")
            return PWAManifest(
                name="学术研究自动化系统",
                short_name="研究助手",
                description="智能化学术研究辅助工具"
            )
    
    def generate_service_worker(self) -> str:
        """生成Service Worker脚本"""
        try:
            sw_script = f"""
// Service Worker for Academic Research Automation System
// Version: {self.pwa_config['cache_version']}
// Generated: {datetime.now().isoformat()}

const CACHE_VERSION = '{self.pwa_config['cache_version']}';
const CACHE_NAMES = {{
    pages: `pages-${{CACHE_VERSION}}`,
    static: `static-${{CACHE_VERSION}}`,
    images: `images-${{CACHE_VERSION}}`,
    api: `api-${{CACHE_VERSION}}`
}};

// 缓存规则
const CACHE_RULES = {json.dumps([
    {
        'pattern': rule.pattern,
        'strategy': rule.strategy.value,
        'cache_name': rule.cache_name,
        'max_age': rule.max_age,
        'max_entries': rule.max_entries,
        'network_timeout': getattr(rule, 'network_timeout', 3000)
    } for rule in self.cache_rules
], indent=2)};

// 预缓存资源列表
const PRECACHE_URLS = [
    '/',
    '/static/css/main.css',
    '/static/js/main.js',
    '/static/icons/icon-192x192.png',
    '/offline.html'
];

// 安装事件
self.addEventListener('install', event => {{
    console.log('Service Worker installing...');
    
    event.waitUntil(
        caches.open(CACHE_NAMES.static)
            .then(cache => {{
                console.log('Precaching static resources');
                return cache.addAll(PRECACHE_URLS);
            }})
            .then(() => {{
                console.log('Service Worker installed successfully');
                return self.skipWaiting();
            }})
            .catch(error => {{
                console.error('Service Worker installation failed:', error);
            }})
    );
}});

// 激活事件
self.addEventListener('activate', event => {{
    console.log('Service Worker activating...');
    
    event.waitUntil(
        Promise.all([
            // 清理旧缓存
            caches.keys().then(cacheNames => {{
                return Promise.all(
                    cacheNames.map(cacheName => {{
                        if (!Object.values(CACHE_NAMES).includes(cacheName)) {{
                            console.log('Deleting old cache:', cacheName);
                            return caches.delete(cacheName);
                        }}
                    }})
                );
            }}),
            // 立即控制所有客户端
            self.clients.claim()
        ]).then(() => {{
            console.log('Service Worker activated successfully');
        }})
    );
}});

// 网络请求拦截
self.addEventListener('fetch', event => {{
    const request = event.request;
    const url = new URL(request.url);
    
    // 只处理同源请求
    if (url.origin !== location.origin) {{
        return;
    }}
    
    // 查找匹配的缓存规则
    const rule = findMatchingRule(url.pathname);
    
    if (rule) {{
        event.respondWith(handleRequest(request, rule));
    }}
}});

// 查找匹配的缓存规则
function findMatchingRule(pathname) {{
    return CACHE_RULES.find(rule => {{
        const regex = new RegExp(rule.pattern);
        return regex.test(pathname);
    }});
}}

// 处理请求
async function handleRequest(request, rule) {{
    const cacheName = CACHE_NAMES[rule.cache_name] || CACHE_NAMES.static;
    
    switch (rule.strategy) {{
        case 'cache_first':
            return cacheFirst(request, cacheName, rule);
        case 'network_first':
            return networkFirst(request, cacheName, rule);
        case 'cache_only':
            return cacheOnly(request, cacheName);
        case 'network_only':
            return networkOnly(request);
        case 'stale_while_revalidate':
            return staleWhileRevalidate(request, cacheName, rule);
        default:
            return networkFirst(request, cacheName, rule);
    }}
}}

// 缓存优先策略
async function cacheFirst(request, cacheName, rule) {{
    try {{
        const cache = await caches.open(cacheName);
        const cachedResponse = await cache.match(request);
        
        if (cachedResponse) {{
            // 检查缓存是否过期
            const cachedDate = new Date(cachedResponse.headers.get('date'));
            const now = new Date();
            const age = (now - cachedDate) / 1000;
            
            if (age < rule.max_age) {{
                return cachedResponse;
            }}
        }}
        
        // 缓存未命中或已过期，从网络获取
        const networkResponse = await fetch(request);
        
        if (networkResponse.ok) {{
            await cache.put(request, networkResponse.clone());
            await cleanupCache(cache, rule.max_entries);
        }}
        
        return networkResponse;
    }} catch (error) {{
        console.error('Cache first strategy failed:', error);
        
        // 网络失败时返回缓存（即使过期）
        const cache = await caches.open(cacheName);
        const cachedResponse = await cache.match(request);
        
        if (cachedResponse) {{
            return cachedResponse;
        }}
        
        // 返回离线页面
        if (request.destination === 'document') {{
            return caches.match('/offline.html');
        }}
        
        throw error;
    }}
}}

// 网络优先策略
async function networkFirst(request, cacheName, rule) {{
    try {{
        const networkResponse = await Promise.race([
            fetch(request),
            new Promise((_, reject) => 
                setTimeout(() => reject(new Error('Network timeout')), rule.network_timeout)
            )
        ]);
        
        if (networkResponse.ok) {{
            const cache = await caches.open(cacheName);
            await cache.put(request, networkResponse.clone());
            await cleanupCache(cache, rule.max_entries);
        }}
        
        return networkResponse;
    }} catch (error) {{
        console.log('Network failed, trying cache:', error.message);
        
        const cache = await caches.open(cacheName);
        const cachedResponse = await cache.match(request);
        
        if (cachedResponse) {{
            return cachedResponse;
        }}
        
        // 返回离线页面
        if (request.destination === 'document') {{
            return caches.match('/offline.html');
        }}
        
        throw error;
    }}
}}

// 仅缓存策略
async function cacheOnly(request, cacheName) {{
    const cache = await caches.open(cacheName);
    return cache.match(request);
}}

// 仅网络策略
async function networkOnly(request) {{
    return fetch(request);
}}

// 过期重新验证策略
async function staleWhileRevalidate(request, cacheName, rule) {{
    const cache = await caches.open(cacheName);
    const cachedResponse = await cache.match(request);
    
    // 后台更新缓存
    const networkResponsePromise = fetch(request).then(response => {{
        if (response.ok) {{
            cache.put(request, response.clone());
            cleanupCache(cache, rule.max_entries);
        }}
        return response;
    }}).catch(error => {{
        console.log('Background update failed:', error);
    }});
    
    // 立即返回缓存响应（如果有）
    return cachedResponse || networkResponsePromise;
}}

// 清理缓存
async function cleanupCache(cache, maxEntries) {{
    const keys = await cache.keys();
    
    if (keys.length > maxEntries) {{
        const keysToDelete = keys.slice(0, keys.length - maxEntries);
        await Promise.all(keysToDelete.map(key => cache.delete(key)));
    }}
}}

// 推送通知处理
self.addEventListener('push', event => {{
    console.log('Push notification received');
    
    if (!event.data) {{
        return;
    }}
    
    try {{
        const data = event.data.json();
        const options = {{
            body: data.body,
            icon: data.icon || '/static/icons/icon-192x192.png',
            badge: data.badge || '/static/icons/badge.png',
            image: data.image,
            tag: data.tag,
            data: data.data,
            actions: data.actions || [],
            requireInteraction: data.requireInteraction || false,
            silent: data.silent || false
        }};
        
        event.waitUntil(
            self.registration.showNotification(data.title, options)
        );
    }} catch (error) {{
        console.error('Push notification handling failed:', error);
    }}
}});

// 通知点击处理
self.addEventListener('notificationclick', event => {{
    console.log('Notification clicked');
    
    event.notification.close();
    
    const data = event.notification.data || {{}};
    const url = data.url || '/';
    
    event.waitUntil(
        clients.matchAll({{ type: 'window', includeUncontrolled: true }})
            .then(clientList => {{
                // 查找已打开的窗口
                for (const client of clientList) {{
                    if (client.url === url && 'focus' in client) {{
                        return client.focus();
                    }}
                }}
                
                // 打开新窗口
                if (clients.openWindow) {{
                    return clients.openWindow(url);
                }}
            }})
    );
}});

// 后台同步
self.addEventListener('sync', event => {{
    console.log('Background sync triggered:', event.tag);
    
    if (event.tag === 'background-sync') {{
        event.waitUntil(doBackgroundSync());
    }}
}});

// 执行后台同步
async function doBackgroundSync() {{
    try {{
        // 获取待同步的数据
        const response = await fetch('/api/sync/pending');
        const pendingData = await response.json();
        
        // 同步数据
        for (const item of pendingData.items || []) {{
            try {{
                await fetch('/api/sync/upload', {{
                    method: 'POST',
                    headers: {{
                        'Content-Type': 'application/json'
                    }},
                    body: JSON.stringify(item)
                }});
                
                console.log('Synced item:', item.id);
            }} catch (error) {{
                console.error('Failed to sync item:', item.id, error);
            }}
        }}
        
        console.log('Background sync completed');
    }} catch (error) {{
        console.error('Background sync failed:', error);
    }}
}}

// 消息处理
self.addEventListener('message', event => {{
    console.log('Message received:', event.data);
    
    if (event.data && event.data.type === 'SKIP_WAITING') {{
        self.skipWaiting();
    }}
}});

console.log('Service Worker script loaded');
"""
            
            pwa_logger.info("Service Worker脚本生成完成")
            return sw_script
            
        except Exception as e:
            pwa_logger.error(f"Service Worker生成失败: {str(e)}")
            return "// Service Worker generation failed"
    
    def create_push_notification(self, title: str, body: str, 
                                options: Optional[Dict[str, Any]] = None) -> PushNotification:
        """创建推送通知"""
        try:
            notification = PushNotification(
                title=title,
                body=body,
                icon=options.get('icon', '/static/icons/icon-192x192.png') if options else '/static/icons/icon-192x192.png',
                badge=options.get('badge', '/static/icons/badge.png') if options else '/static/icons/badge.png',
                image=options.get('image', '') if options else '',
                tag=options.get('tag', '') if options else '',
                data=options.get('data', {}) if options else {},
                actions=options.get('actions', []) if options else [],
                ttl=options.get('ttl', 86400) if options else 86400
            )
            
            pwa_logger.info(f"推送通知创建: {title}")
            return notification
            
        except Exception as e:
            pwa_logger.error(f"推送通知创建失败: {str(e)}")
            return PushNotification(title="通知", body="")
    
    def register_push_subscription(self, subscription_data: Dict[str, Any]) -> bool:
        """注册推送订阅"""
        try:
            subscription_id = hashlib.md5(
                json.dumps(subscription_data, sort_keys=True).encode()
            ).hexdigest()
            
            self.push_subscriptions.add(subscription_id)
            
            pwa_logger.info(f"推送订阅注册成功: {subscription_id}")
            return True
            
        except Exception as e:
            pwa_logger.error(f"推送订阅注册失败: {str(e)}")
            return False
    
    def schedule_background_sync(self, task_name: str, data: Dict[str, Any]) -> str:
        """安排后台同步任务"""
        try:
            task_id = f"sync_{int(datetime.now().timestamp())}_{len(self.background_sync_tasks)}"
            
            sync_task = {
                'task_id': task_id,
                'task_name': task_name,
                'data': data,
                'created_at': datetime.now().isoformat(),
                'status': 'pending',
                'retry_count': 0,
                'max_retries': 3
            }
            
            self.background_sync_tasks.append(sync_task)
            
            pwa_logger.info(f"后台同步任务已安排: {task_id}")
            return task_id
            
        except Exception as e:
            pwa_logger.error(f"后台同步任务安排失败: {str(e)}")
            return ""
    
    def generate_offline_page(self) -> str:
        """生成离线页面"""
        try:
            offline_html = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>离线模式 - 学术研究自动化系统</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            margin: 0;
            padding: 0;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
        }
        
        .offline-container {
            text-align: center;
            padding: 2rem;
            max-width: 500px;
        }
        
        .offline-icon {
            font-size: 4rem;
            margin-bottom: 1rem;
            opacity: 0.8;
        }
        
        .offline-title {
            font-size: 2rem;
            font-weight: 300;
            margin-bottom: 1rem;
        }
        
        .offline-message {
            font-size: 1.1rem;
            line-height: 1.6;
            margin-bottom: 2rem;
            opacity: 0.9;
        }
        
        .offline-actions {
            display: flex;
            gap: 1rem;
            justify-content: center;
            flex-wrap: wrap;
        }
        
        .btn {
            padding: 0.75rem 1.5rem;
            border: 2px solid rgba(255, 255, 255, 0.3);
            background: rgba(255, 255, 255, 0.1);
            color: white;
            text-decoration: none;
            border-radius: 25px;
            transition: all 0.3s ease;
            backdrop-filter: blur(10px);
        }
        
        .btn:hover {
            background: rgba(255, 255, 255, 0.2);
            border-color: rgba(255, 255, 255, 0.5);
            transform: translateY(-2px);
        }
        
        .btn-primary {
            background: rgba(33, 150, 243, 0.3);
            border-color: rgba(33, 150, 243, 0.5);
        }
        
        .offline-features {
            margin-top: 3rem;
            text-align: left;
        }
        
        .feature-list {
            list-style: none;
            padding: 0;
        }
        
        .feature-item {
            padding: 0.5rem 0;
            display: flex;
            align-items: center;
            opacity: 0.8;
        }
        
        .feature-icon {
            margin-right: 0.5rem;
            font-size: 1.2rem;
        }
        
        @media (max-width: 600px) {
            .offline-container {
                padding: 1rem;
            }
            
            .offline-title {
                font-size: 1.5rem;
            }
            
            .offline-actions {
                flex-direction: column;
                align-items: center;
            }
            
            .btn {
                width: 200px;
            }
        }
    </style>
</head>
<body>
    <div class="offline-container">
        <div class="offline-icon">📡</div>
        <h1 class="offline-title">当前处于离线模式</h1>
        <p class="offline-message">
            网络连接似乎出现了问题，但您仍然可以使用部分功能。
            我们会在网络恢复时自动同步您的数据。
        </p>
        
        <div class="offline-actions">
            <button class="btn btn-primary" onclick="checkConnection()">重新连接</button>
            <a href="/" class="btn">返回首页</a>
        </div>
        
        <div class="offline-features">
            <h3>离线可用功能：</h3>
            <ul class="feature-list">
                <li class="feature-item">
                    <span class="feature-icon">📝</span>
                    查看已缓存的项目和文档
                </li>
                <li class="feature-item">
                    <span class="feature-icon">✏️</span>
                    编辑本地保存的内容
                </li>
                <li class="feature-item">
                    <span class="feature-icon">📊</span>
                    查看离线分析结果
                </li>
                <li class="feature-item">
                    <span class="feature-icon">🔄</span>
                    自动后台同步（网络恢复后）
                </li>
            </ul>
        </div>
    </div>
    
    <script>
        function checkConnection() {
            if (navigator.onLine) {
                window.location.reload();
            } else {
                alert('网络仍未连接，请检查您的网络设置。');
            }
        }
        
        // 监听网络状态变化
        window.addEventListener('online', function() {
            console.log('网络已恢复');
            setTimeout(() => {
                window.location.reload();
            }, 1000);
        });
        
        window.addEventListener('offline', function() {
            console.log('网络已断开');
        });
        
        // 显示网络状态
        function updateNetworkStatus() {
            const status = navigator.onLine ? '在线' : '离线';
            console.log('当前网络状态:', status);
        }
        
        updateNetworkStatus();
        setInterval(updateNetworkStatus, 5000);
    </script>
</body>
</html>
"""
            
            pwa_logger.info("离线页面生成完成")
            return offline_html
            
        except Exception as e:
            pwa_logger.error(f"离线页面生成失败: {str(e)}")
            return "<html><body><h1>离线模式</h1><p>网络连接不可用</p></body></html>"
    
    def get_pwa_status(self) -> Dict[str, Any]:
        """获取PWA状态"""
        try:
            return {
                'pwa_enabled': self.pwa_config['enable_service_worker'],
                'cache_version': self.pwa_config['cache_version'],
                'service_worker_registered': True,  # 实际应该检查注册状态
                'push_notifications_enabled': self.pwa_config['enable_push_notifications'],
                'background_sync_enabled': self.pwa_config['enable_background_sync'],
                'push_subscriptions_count': len(self.push_subscriptions),
                'background_sync_tasks_count': len(self.background_sync_tasks),
                'cache_rules_count': len(self.cache_rules),
                'update_available': self.update_available,
                'last_update_check': self.last_update_check.isoformat(),
                'features': {
                    'offline_support': True,
                    'push_notifications': True,
                    'background_sync': True,
                    'app_shortcuts': True,
                    'installable': True,
                    'responsive_design': True
                },
                'performance': {
                    'cache_hit_rate': 0.85,  # 模拟数据
                    'offline_page_loads': 23,  # 模拟数据
                    'background_syncs_completed': 156  # 模拟数据
                }
            }
            
        except Exception as e:
            pwa_logger.error(f"获取PWA状态失败: {str(e)}")
            return {'error': str(e)}
    
    def update_cache_rules(self, new_rules: List[Dict[str, Any]]) -> bool:
        """更新缓存规则"""
        try:
            self.cache_rules = []
            
            for rule_data in new_rules:
                cache_rule = CacheRule(
                    pattern=rule_data['pattern'],
                    strategy=CacheStrategy(rule_data['strategy']),
                    cache_name=rule_data['cache_name'],
                    max_age=rule_data.get('max_age', 86400),
                    max_entries=rule_data.get('max_entries', 100),
                    network_timeout=rule_data.get('network_timeout', 3000)
                )
                self.cache_rules.append(cache_rule)
            
            # 更新缓存版本
            self.pwa_config['cache_version'] = f"v{datetime.now().strftime('%Y%m%d_%H%M%S')}"
            
            pwa_logger.info(f"缓存规则已更新: {len(self.cache_rules)} 条规则")
            return True
            
        except Exception as e:
            pwa_logger.error(f"缓存规则更新失败: {str(e)}")
            return False


# 示例使用
if __name__ == "__main__":
    # 创建PWA服务
    pwa_service = PWAService()
    
    print("=== PWA支持服务测试 ===")
    
    # 生成应用清单
    print("1. 生成PWA应用清单")
    app_config = {
        'name': '学术研究自动化系统',
        'short_name': '研究助手',
        'description': '智能化学术研究辅助工具'
    }
    
    manifest = pwa_service.generate_manifest(app_config)
    print(f"应用名称: {manifest.name}")
    print(f"图标数量: {len(manifest.icons)}")
    print(f"快捷方式数量: {len(manifest.shortcuts)}")
    
    # 生成Service Worker
    print("\n2. 生成Service Worker")
    sw_script = pwa_service.generate_service_worker()
    print(f"Service Worker脚本长度: {len(sw_script)} 字符")
    
    # 创建推送通知
    print("\n3. 创建推送通知")
    notification = pwa_service.create_push_notification(
        "新的研究进展",
        "您的AI研究项目有新的分析结果",
        {
            'icon': '/static/icons/notification.png',
            'data': {'project_id': 'proj_001'},
            'actions': [
                {'action': 'view', 'title': '查看详情'},
                {'action': 'dismiss', 'title': '忽略'}
            ]
        }
    )
    print(f"通知标题: {notification.title}")
    print(f"通知操作: {len(notification.actions)} 个")
    
    # 注册推送订阅
    print("\n4. 注册推送订阅")
    subscription_data = {
        'endpoint': 'https://fcm.googleapis.com/fcm/send/test',
        'keys': {
            'p256dh': 'test_key',
            'auth': 'test_auth'
        }
    }
    
    success = pwa_service.register_push_subscription(subscription_data)
    print(f"订阅注册结果: {success}")
    
    # 安排后台同步
    print("\n5. 安排后台同步")
    task_id = pwa_service.schedule_background_sync(
        'sync_project_data',
        {'project_id': 'proj_001', 'data': {'progress': 75}}
    )
    print(f"同步任务ID: {task_id}")
    
    # 生成离线页面
    print("\n6. 生成离线页面")
    offline_page = pwa_service.generate_offline_page()
    print(f"离线页面长度: {len(offline_page)} 字符")
    
    # 获取PWA状态
    print("\n7. PWA状态")
    status = pwa_service.get_pwa_status()
    print(json.dumps(status, indent=2, ensure_ascii=False))